/**
 *
 */
package org.t2.backstage.module.player;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.banish.sql.core.annotation.SplitTable;
import org.banish.sql.core.dao.Dao;
import org.banish.sql.core.datasource.IDataSource;
import org.banish.sql.core.util.QuerySet;
import org.gaming.backstage.PageData;
import org.gaming.service.advice.ResponseResult;
import org.gaming.service.apidoc.annotation.ApiDocument;
import org.gaming.service.asserts.Asserts;
import org.gaming.service.repository.Repository;
import org.gaming.tool.DateTimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.t2.backstage.module.TipsCode;
import org.t2.backstage.module.gameserver.model.GameChannel;
import org.t2.backstage.module.gameserver.model.GameServer;
import org.t2.backstage.module.gameserver.service.DataBaseManager;
import org.t2.backstage.module.gameserver.service.GameChannelService;
import org.t2.backstage.module.gameserver.service.GameServerService;
import org.t2.backstage.module.player.model.Player;
import org.t2.backstage.module.player.query.PlayerLogQuery;
import org.t2.backstage.module.player.query.PlayerQuery;
import org.t2.backstage.module.player.service.PlayerService;
import org.t2.backstage.module.player.vo.PlayerInfoVo;
import org.t2.backstage.module.player.vo.PlayerNumberLogVo;
import org.t2.backstage.util.T2HttpUtil;

import sh.t2.share.apiutil.GameApi;
import sh.t2.share.module.player.PlayerApiProtocol.PlayerDetailRequest;
import sh.t2.share.module.player.PlayerApiProtocol.PlayerDetailResponse;
import sh.t2.share.module.player.PlayerApiProtocol.PlayerForbidRequest;
import sh.t2.share.module.player.PlayerApiProtocol.PlayerForbidResponse;
import sh.t2.share.module.player.PlayerApiProtocol.PlayerHeroRequest;
import sh.t2.share.module.player.PlayerApiProtocol.PlayerHeroResponse;
import sh.t2.share.module.player.PlayerApiProtocol.PlayerOfflineRequest;
import sh.t2.share.module.player.PlayerApiProtocol.PlayerOfflineResponse;
import sh.t2.share.module.player.form.HeroData;
import sh.t2.share.module.player.form.PlayerDetailData;
import sh.t2.share.module.player.form.PlayerTable;
import sh.t2.share.module.player.form.PlayerTable.PlayerData;
import sh.t2.share.module.player.log.PlayerDiamondLog;
import sh.t2.share.module.player.log.PlayerFeatherLog;
import sh.t2.share.module.player.log.PlayerGoldLog;
import sh.t2.share.module.player.log.PlayerHeroNumLog;
import sh.t2.share.module.player.log.PlayerLevelLog;
import sh.t2.share.module.player.log.PlayerMissionLog;
import sh.t2.share.module.player.log.PlayerMuscleLog;
import sh.t2.share.module.player.log.PlayerNumberLog;
import sh.t2.share.module.player.log.PlayerPointLog;
import sh.t2.share.module.player.log.PlayerTreasureNumLog;
import sh.t2.share.module.player.log.PlayerTreasureSummonLog;
import sh.t2.share.module.player.log.PlayerWeaponNumLog;
import sh.t2.share.module.player.log.PlayerWeaponSummonLog;

/**
 * @author YY
 *
 */
@Controller
public class PlayerController {

	private static Logger logger = LoggerFactory.getLogger(PlayerController.class);
	
	@Autowired
	private PlayerService playerService;
	@Autowired
	private GameChannelService gameChannelService;
	@Autowired
	private GameServerService gameServerService;
	@Autowired
	private DataBaseManager dataBaseManager;

	@ApiDocument("请求玩家数据")
	@RequestMapping(value = "/player/data.auth")
	@ResponseBody
	public PageData<PlayerInfoVo> data(PlayerQuery query) {
		QuerySet querySet = new QuerySet();
		//渠道选择
		if(query.getChannels() != null && !query.getChannels().isEmpty()) {
			querySet.findInSet("channel_id", query.getChannels());
		}
		//服务器选择
		if(query.getServerUids() != null && !query.getServerUids().isEmpty()) {
			Set<Integer> serverIdSet = new HashSet<>();
			for(int serverUid : query.getServerUids()) {
				GameServer gameServer = gameServerService.getEntity(0, serverUid);
				if(gameServer == null) {
					continue;
				}
				serverIdSet.add(gameServer.getServerId());
			}
			if(!serverIdSet.isEmpty()) {
				querySet.findInSet("server_id", serverIdSet);
			}
		}
		//开始时间
		long startTime = query.getStartTime() * 1000L;
		if(startTime > 0) {
			String startBorn = DateTimeUtil.formatMillis(DateTimeUtil.YYYY_MM_DD, startTime);
			querySet.addCondition("born_time >= ?", startBorn);
		}
		//结束时间
		long endTime = query.getEndTime() * 1000L;
		if(endTime > 0) {
			String endBorn = DateTimeUtil.formatMillis(DateTimeUtil.YYYY_MM_DD, endTime + DateTimeUtil.ONE_DAY_MILLIS);
			querySet.addCondition("born_time <= ?", endBorn);
		}
		if (query.getPlayerId() > 0) {
			querySet.addCondition("id like ?", "%" + query.getPlayerId());
		}
		if (query.getName() != null && !"".equals(query.getName())) {
			querySet.addCondition("nick like ?", "%" + query.getName() + "%");
		}
		if (query.getOpenId() != null && !"".equals(query.getOpenId())) {
			querySet.addCondition("open_id like ?", "%" + query.getOpenId() + "%");
		}
		querySet.orderBy("order by id desc");
		querySet.limit(query.getPage(), query.getLimit());
		querySet.formWhere();

		PageData<Player> pageData = playerService.query(querySet);
		
		Map<Long, String> channelNames = new HashMap<>();
		Map<String, String> serverNames = new HashMap<>();
		
		PageData<PlayerInfoVo> result = new PageData<>();
		for(int i = 0; i < pageData.getData().size(); i++) {
			Player player = pageData.getData().get(i);
			PlayerInfoVo vo = new PlayerInfoVo();
			vo.setId(i + 1);
			String channelName = channelNames.get(player.getChannelId());
			if(channelName == null) {
				GameChannel gameChannel = gameChannelService.getEntity(0, player.getChannelId());
				if(gameChannel != null) {
					channelName = gameChannel.getName();
				} else {
					channelName = "";
				}
				channelNames.put(player.getChannelId(), channelName);
			}
			vo.setChannelInfo(channelName + "[" + player.getChannelId() + "]");
			
			String serverName = serverNames.get(player.getChannelId() + "_" + player.getServerId());
			if(serverName == null) {
				try {
					GameServer gameServer = gameServerService.getByPlatformAndServer(player.getPlatformId(), player.getServerId());
					if(gameServer != null) {
						serverName = gameServer.getName();
					} else {
						serverName = "";
					}
				} catch (Exception e) {
					serverName = "";
				}
				serverNames.put(player.getChannelId() + "_" + player.getServerId(), serverName);
			}
			vo.setServerInfo(player.getServerId() + "-" + serverName);
			vo.setPlayerId(player.getId());
			vo.setOpenId(player.getOpenId());
			vo.setNick(player.getNick());
			vo.setLevel(player.getLevel());
			vo.setVipLevel(player.getVipLevel());
			vo.setRecharge(player.getRecharge() / 100);
			vo.setBornTime(player.getBornTime());
			vo.setLastLoginTime(player.getLastLoginTime());
			vo.setLastLogoutTime(player.getLastLogoutTime());
			vo.setForbidEndTime(player.getForbidEndTime());
			vo.setOnline(player.isOnline());
			vo.setLoginIp(player.getLoginIp());
			vo.setDeviceModel(player.getDeviceModel());
			vo.setForbidRankTime(player.getForbidRankTime());
			result.getData().add(vo);
		}
		result.setCount(pageData.getCount());
		return result;
	}

	@ApiDocument("请求玩家数据详情")
	@RequestMapping(value = "/player/detail.auth")
	@ResponseBody
	public PageData<PlayerDetailData> detail(@RequestParam("playerId") long playerId) {
		Player player = playerService.getEntity(playerId);
		Asserts.isTrue(player != null, TipsCode.PLAYER_NOT_EXIST, playerId);

		GameServer gameServer = gameServerService.getByPlatformAndServer(player.getPlatformId(), player.getServerId());

		PlayerDetailRequest request = new PlayerDetailRequest();
		request.playerId = playerId;
		ResponseResult<PlayerDetailResponse> response = T2HttpUtil.jsonPost(gameServer, GameApi.playerDetails, request,
				PlayerDetailResponse.class);
		Asserts.isTrue(response.getCode() == 0, TipsCode.PLAYER_NOT_EXIST, playerId);
		
		PageData<PlayerDetailData> pageData = new PageData<>();
		pageData.setCount(1);
		pageData.getData().add(response.getData().detail);
		return pageData;
	}

	@ApiDocument("请求玩家英雄数据详情")
	@RequestMapping(value = "/player/hero.auth")
	@ResponseBody
	public PageData<HeroData> heorDatas(@RequestParam("playerId") long playerId) {
		Player player = playerService.getEntity(playerId);
		Asserts.isTrue(player != null, TipsCode.PLAYER_NOT_EXIST, playerId);

		GameServer gameServer = gameServerService.getByPlatformAndServer(player.getPlatformId(), player.getServerId());
		
		PlayerHeroRequest request = new PlayerHeroRequest();
		request.playerId = playerId;
		ResponseResult<PlayerHeroResponse> response = T2HttpUtil.jsonPost(gameServer, GameApi.playerHeros, request,
				PlayerHeroResponse.class);
		Asserts.isTrue(response.getCode() == 0, TipsCode.PLAYER_NOT_EXIST, playerId);
		
		PageData<HeroData> pageData = new PageData<>();
		pageData.setCount(response.getData().heroes.size());
		pageData.getData().addAll(response.getData().heroes);
		return pageData;
	}
	
	@ApiDocument("上报玩家数据，给游戏服的接口")
	@RequestMapping(value = GameApi.playerReport)
	@ResponseBody
	public void playerReport(@RequestBody PlayerTable playerTable) {
		List<Player> updateList = new ArrayList<>();
		for(PlayerData playerData : playerTable.getDatas()) {
			Player player = new Player();
			player.setId(playerData.getPlayerId());
			player.setPlatformId(playerData.getPlatformId());
			player.setChannelId(playerData.getChannelId());
			player.setServerId(playerData.getServerId());
			player.setOpenId(playerData.getOpenId());
			player.setNick(playerData.getNick());
			player.setLevel(playerData.getLevel());
			player.setVipLevel(playerData.getVipLevel());
			player.setOnline(playerData.isOnline());
			player.setBornTime(playerData.getBornTime());
			player.setLastLoginTime(playerData.getLastLoginTime());
			player.setLastLogoutTime(playerData.getLastLogoutTime());
			player.setForbidEndTime(playerData.getForbidEndTime());
			player.setRecharge(playerData.getRecharge());
			player.setLoginIp(playerData.getLoginIp());
			player.setDeviceModel(playerData.getDeviceModel());
			player.setForbidRankTime(playerData.getForbidRankTime());
			updateList.add(player);
		}
		playerService.insertUpdate(updateList);
		logger.info("收到服务器{}上报的玩家数量{}", playerTable.getServerId(), playerTable.getDatas().size());
	}
	
	@ApiDocument("请求封禁玩家")
	@RequestMapping(value = "/playerCurrOnline/forbid.auth")
	@ResponseBody
	public void forbid(@RequestParam("playerId") long playerId, @RequestParam("forbidEndTime") long forbidEndTime) {
		Player player = playerService.getEntity(playerId);
		GameServer gameServer = gameServerService.getByPlatformAndServer(player.getPlatformId(), player.getServerId());
		
		
		PlayerForbidRequest request = new PlayerForbidRequest();
		request.playerId = playerId;
		request.forbidEndTime = forbidEndTime;
		ResponseResult<PlayerForbidResponse> response = T2HttpUtil.jsonPost(gameServer, GameApi.playerForbid, request, PlayerForbidResponse.class);
		Asserts.isTrue(response != null && response.getCode() == 0, TipsCode.PLAYER_FORBID_FAIL);
	}
	
	
	@ApiDocument("请求封榜玩家")
	@RequestMapping(value = "/playerCurrOnline/forbidRank.auth")
	@ResponseBody
	public void forbidRank(@RequestParam("playerId") long playerId, @RequestParam("forbidEndTime") long forbidEndTime) {
		logger.info("封榜{}-{}", playerId, forbidEndTime);
		Player player = playerService.getEntity(playerId);
		GameServer gameServer = gameServerService.getByPlatformAndServer(player.getPlatformId(), player.getServerId());
		
		PlayerForbidRequest request = new PlayerForbidRequest();
		request.playerId = playerId;
		request.forbidEndTime = forbidEndTime;
		ResponseResult<PlayerForbidResponse> response = T2HttpUtil.jsonPost(gameServer, GameApi.playerForbidRank, request, PlayerForbidResponse.class);
		Asserts.isTrue(response != null && response.getCode() == 0, TipsCode.PLAYER_FORBID_FAIL);
	}
	

	@ApiDocument("踢玩家下线")
	@RequestMapping(value = "/playerCurrOnline/forcedOffLine.auth")
	@ResponseBody
	public void forcedOffLine(@RequestParam("playerId") long playerId) {
		Player player = playerService.getEntity(playerId);
		GameServer gameServer = gameServerService.getByPlatformAndServer(player.getPlatformId(), player.getServerId());
		
		PlayerOfflineRequest request = new PlayerOfflineRequest();
		request.playerId = playerId;
		ResponseResult<PlayerOfflineResponse> response = T2HttpUtil.jsonPost(gameServer, GameApi.playerForcedOffline, request, PlayerOfflineResponse.class);
		Asserts.isTrue(response != null && response.getCode() == 0, TipsCode.PLAYER_FORCED_OFFLINE_FAIL);
	}
	
	
	public static Map<String, Class<? extends PlayerNumberLog>> logClassMap = new HashMap<>();
	static {
		logClassMap.put("level", PlayerLevelLog.class);	//等级
		logClassMap.put("mission", PlayerMissionLog.class);//关卡
		logClassMap.put("gold", PlayerGoldLog.class);//金币
		logClassMap.put("diamond", PlayerDiamondLog.class);//钻石
		logClassMap.put("muscle", PlayerMuscleLog.class);//体力
		logClassMap.put("point", PlayerPointLog.class);//积分
		logClassMap.put("feather", PlayerFeatherLog.class);//羽毛
		logClassMap.put("heroNum", PlayerHeroNumLog.class);//英雄数量
		logClassMap.put("treasureSummon", PlayerTreasureSummonLog.class);//宝藏召唤数量
		logClassMap.put("treasureNum", PlayerTreasureNumLog.class);//宝藏数量
		logClassMap.put("weaponSummon", PlayerWeaponSummonLog.class);//武器召唤数量
		logClassMap.put("weaponNum", PlayerWeaponNumLog.class);//武器数量
	}
	
	@ApiDocument("请求玩家数据变化明细")
	@RequestMapping(value = "/player/log.auth")
	@ResponseBody
	public PageData<PlayerNumberLogVo> numberLogs(PlayerLogQuery query) {
		Class<? extends PlayerNumberLog> clazz = logClassMap.get(query.getModule());
		Asserts.isTrue(clazz != null, TipsCode.ERROR_PARAM);
		
		Player player = playerService.getEntity(query.getPlayerId());
		Asserts.isTrue(player != null, TipsCode.PLAYER_NOT_EXIST, query.getPlayerId());
		
		QuerySet querySet = new QuerySet();
		//开始时间
		long startTime = query.getStartTime() * 1000L;
		if(startTime == 0) {
			startTime = DateTimeUtil.monthZeroMillis();
		}
		String startBorn = DateTimeUtil.formatMillis(DateTimeUtil.YYYY_MM_DD, startTime);
		querySet.addCondition("insert_time >= ?", startBorn);
		//结束时间
		long endTime = query.getEndTime() * 1000L;
		if(endTime > 0) {
			String endBorn = DateTimeUtil.formatMillis(DateTimeUtil.YYYY_MM_DD, endTime);
			querySet.addCondition("insert_time <= ?", endBorn);
		}
		querySet.addCondition("player_id = ?", player.getId());
		querySet.limit(query.getPage(), 50);
		querySet.orderBy("order by id desc");
		querySet.formWhere();
		
		GameServer gameServer = gameServerService.getByPlatformAndServer(player.getPlatformId(), player.getServerId());
		
		IDataSource dataBase = dataBaseManager.getLogDb(gameServer.getId());
		if(dataBase == null) {
			logger.error("进行服务器{}-{}的LTV统计中，未定义数据库连接信息", gameServer.getId(), gameServer.getName());
			return new PageData<>();
		}
		
		String tableName = Repository.getTableName(clazz);
		SplitTable logTable = clazz.getAnnotation(SplitTable.class);
		if(logTable != null) {
			//需要按月份查询
			String yearMonth = DateTimeUtil.formatMillis(DateTimeUtil.YYYYMM, startTime);
			tableName = tableName + "_" + yearMonth;
		} else {
			//可以直接查
		}
		
		String sql = "select * from " + tableName + " " + querySet.getWhere();
		List<PlayerNumberLogVo> logs = Dao.queryAliasObjects(dataBase, PlayerNumberLogVo.class, sql, querySet.getParams());
		
		long count = Dao.count(dataBase, tableName, querySet.getCountWhere(), querySet.getCountParams());
		
		PageData<PlayerNumberLogVo> pageData = new PageData<>();
		pageData.setCount(count);
		pageData.setData(logs);
		return pageData;
	}
}
